﻿namespace fpsrpg
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Xml.Serialization;

    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Audio;
    using Microsoft.Xna.Framework.Content;
    using Microsoft.Xna.Framework.GamerServices;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;
    using Microsoft.Xna.Framework.Storage;

    #region Enumerations

    public enum PlayerClass
    {
        Tank,
        Healer,
        Dps,
        Utility
    }

    #endregion Enumerations

    public class Player : Unit
    {
        #region Fields

        public int Customize_body;
        public Color Customize_body_color;
        public string Customize_body_title;
        public Hats hats;
        public ContentManager mContentManager;
        public int number_of_bodies = 4;
        public int number_of_hats = 6;

        const int MOVE_DOWN = 1;
        const int MOVE_LEFT = -1;
        const int MOVE_RIGHT = 1;
        const int MOVE_UP = -1;
        const int START_Position_X = 125;
        const int START_Position_Y = 245;
        const int WIZARD_SPEED = 130;

        static ulong[] XPPerLevel = { 400, 1000 };

        MouseState aCurrentMouseState = Mouse.GetState();
        AmmoContainer ammo = new AmmoContainer();
        KeyboardState mPreviousKeyboardState;
        MouseState mPreviousMouseState;
        string name = Properties.Settings.Default.LocalPlayerName;
        bool shot;
        Weapons weapons;
        string WIZARD_ASSETNAME;
        ulong xp;

        #endregion Fields

        #region Constructors

        public Player()
            : base()
        {
            weapons = new Weapons();
               weapon = new ScriptedWeapons.Weapon_Hands();
               //Microsoft.Xna.Framework.GamerServices.SignedInGamer.SignedIn += new EventHandler<SignedInEventArgs>(SignedInGamer_SignedIn);
        }

        #endregion Constructors

        #region Properties

        public override string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
        }

        public Weapon weapon
        {
            get { return weapons.GetWeapon(); }
            private set {}
        }

        #endregion Properties

        #region Methods

        public void AddXP(ulong to_add)
        {
            if ((xp + to_add) >= XPPerLevel[Level - 1])
            {
                ulong remains = to_add;
                remains -= (XPPerLevel[Level - 1] - xp);
                LevelUp();
                AddXP(remains);
            }
            else
            {
                xp += to_add;
            }
        }

        public void Customize_body_switch(int Customize_body_number, ContentManager TheContentManager)
        {
            switch (Customize_body_number)
            {
                case 1:
                    WIZARD_ASSETNAME = "customize_body1";
                    Customize_body_title = "Body 1";
                    base.LoadContent(TheContentManager, WIZARD_ASSETNAME);
                    break;
                case 2:
                    WIZARD_ASSETNAME = "customize_body2";
                    Customize_body_title = "Body 2";
                    base.LoadContent(TheContentManager, WIZARD_ASSETNAME);
                    break;
                case 3:
                    WIZARD_ASSETNAME = "customize_body3";
                    Customize_body_title = "Arctic camo 1";
                    base.LoadContent(TheContentManager, WIZARD_ASSETNAME);
                    break;
                case 4:
                    WIZARD_ASSETNAME = "customize_body4";
                    Customize_body_title = "Arctic camo 2";
                    base.LoadContent(TheContentManager, WIZARD_ASSETNAME);
                    break;
                default:
                    WIZARD_ASSETNAME = "customize_body1";
                    Customize_body_title = "Default body";
                    base.LoadContent(TheContentManager, WIZARD_ASSETNAME);
                    break;
            }
            Properties.Settings.Default.Save();
        }

        public override void Draw(SpriteBatch spriteBatch, Color OptionalColor)
        {
                OptionalColor = this.Customize_body_color;

            //            spriteBatch.Draw(mSpriteTexture, Position, null, OptionalColor, Rotation, new Vector2(Size.Width / 2, Size.Height / 2), Scale, SpriteEffects.None, 0);
            base.Draw(spriteBatch, OptionalColor);

            //Draw the weapon
            if(weapon.WeaponTexture != null)
            spriteBatch.Draw(weapon.WeaponTexture, new Rectangle((int)Position.X, (int)Position.Y, weapon.WeaponTexture.Width, weapon.WeaponTexture.Height), null, Color.White, Rotation, new Vector2(weapon.WeaponTexture.Width / 2 - 26, weapon.WeaponTexture.Height / 2), SpriteEffects.None, 0);

            //Draw teh leet hat.
            if (hats.Customize_hat > 0)
                spriteBatch.Draw(hats.HatTexture, new Rectangle((int)Position.X, (int)Position.Y, hats.HatTexture.Width, hats.HatTexture.Height), null, hats.Customize_hat_color, Rotation, new Vector2(hats.HatTexture.Width / 2 + 5, hats.HatTexture.Height / 2), SpriteEffects.None, 1);

            //Draw the muzzle flash
            if (shot)
            {
                spriteBatch.Draw(weapon.muzzleflash, new Rectangle((int)Position.X, (int)Position.Y, weapon.muzzleflash.Width, weapon.muzzleflash.Height), null, Color.White, Rotation, new Vector2(weapon.muzzleflash.Width / 2 - (23 + weapon.WeaponTexture.Width), weapon.muzzleflash.Height / 2), SpriteEffects.None, 1);
                shot = false;
            }
        }

        public string GetAmmoString()
        {
            if (weapon.MaxAmmo == 0)
                return "";
            return string.Format("{0}/{1}", weapon.AmmoInClip, ammo.ForType(weapon.ammoType));
        }

        public string GetXpString()
        {
            return string.Format("{0}/{1}", xp, XPPerLevel[Level -1]);
        }

        public string GetBulletImpactSound()
        {
            return weapon.BulletImpactSound;
        }

        public string GetBulletTexture()
        {
            return weapon.WeaponBullet;
        }

        public double GetShootDelay()
        {
            return weapon.cooldown;
        }

        public int GetWeaponDamage()
        {
            return weapon.Damage;
        }

        public Texture2D GetWeaponHudTexture()
        {
            return weapon.WeaponHudTexture;
        }

        public string GetWeaponSound()
        {
            return weapon.WeaponSound;
        }

        public ulong GetXP()
        {
            return xp;
        }

        public float GetXpFrac()
        {
            return (float)xp / (float)XPPerLevel[Level - 1];
        }

        public override void KilledOther(Unit victim)
        {
            uint to_add_xp = (Level * 5) + 45 + (victim.Level * 5 + 45);
            AddXP(to_add_xp);
            //if (Randomizer.NextDouble() > 0.5f)
                ammo.Pickup(weapon.ammoType, 30);

            Program.gameinstance.AddMessageBox(String.Format("Player killed of {0} who is of type {1} ",victim,victim.GetType().Name));
        }

        public void LevelUp()
        {
            Level++;
            xp = 0;
        }

        public void Load(StorageDevice dev)
        {
            StorageContainer strcnt = dev.OpenContainer("toplands");

            var fileName = Path.Combine(strcnt.Path, "plrSave.plr.save");

            FileStream stream = File.Open(fileName, FileMode.Open);

            XmlSerializer Ser = new XmlSerializer(typeof(PlayerSaveData));

            PlayerSaveData svd = (PlayerSaveData)Ser.Deserialize(stream);

            this.Customize_body_color = svd.BodyColor;
            this.Customize_body_switch(svd.BodyType, mContentManager);

            this.hats.Customize_hat_color = svd.Hat.Col;
            this.hats.Customize_hat_switch(svd.Hat.Id, mContentManager);

            this.SwitchWeapon(svd.Weapons.Id);

            this.Position = svd.Location;
            mCurrentState = State.Walking;
            mSpeed.X = WIZARD_SPEED;
            mDirection.X = MOVE_RIGHT;

            xp = svd.xp;
            Level = svd.Level;

            this.Name = svd.PlayerName;

            stream.Close();
            strcnt.Dispose();
        }

        public void LoadContent(ContentManager TheContentManager)
        {
            mContentManager = TheContentManager;
            hats = new Hats();

            Position = new Vector2(START_Position_X, START_Position_Y);

            Customize_body_color = Color.White;

            Customize_body = Properties.Settings.Default.Customize_body;

            Customize_body_switch(Properties.Settings.Default.Customize_body,TheContentManager);

            Health = 100;

            base.LoadContent(mContentManager, WIZARD_ASSETNAME);
        }

        public void NextWeapon()
        {
            weapons.Next();
        }

        public void PreviousWeapon()
        {
            weapons.Previous();
        }

        public void Save(StorageDevice dev)
        {
            PlayerSaveData p = new PlayerSaveData();

            p.Location = this.Position;
            p.PlayerName = this.Name;

            p.xp = xp;
            p.Level = Level;

            p.Hat = new HatSaveData();
            p.Hat.Id = hats.Customize_hat;
            p.Hat.Col = hats.Customize_hat_color;

            p.BodyColor = this.Customize_body_color;
            p.BodyType = this.Customize_body;

            p.Weapons = new WeaponSaveData();
            p.Weapons.Id = 1;
            //p.Weapons = weapons.

            StorageContainer strcnt = dev.OpenContainer("toplands");

            var fileName = Path.Combine(strcnt.Path, "plrSave.plr.save");

            FileStream stream = File.Open(fileName, FileMode.Create);

            XmlSerializer ser = new XmlSerializer(typeof(PlayerSaveData));
            ser.Serialize(stream, p);

            stream.Close();

            strcnt.Dispose();
        }

        public void Shoot(Bullets bullet_collection,SoundBank soundBank)
        {
            if (weapon.CanShoot())
            {
                shot = true;
                weapon.Shoot();
                Recoil(aCurrentMouseState, mPreviousMouseState);
                bullet_collection.FireBullet(this, soundBank, GetWeaponSound());
            }
            else
            {
                if (weapon.AmmoInClip == 0)
                {
                    Reload();
                }

                if(weapon.GetType() != typeof(ScriptedWeapons.Weapon_Hands) && (weapon.AmmoInClip == 0))
                    soundBank.PlayCue("Clip_Empty");

            }
        }

        public void SwitchWeapon(uint WeaponId)
        {
            weapons.Switch(WeaponId);
        }

        public void Update(GameTime theGameTime,ContentManager TheContentManager)
        {
            KeyboardState aCurrentKeyboardState = Keyboard.GetState();
            MouseState aCurrentMouseState = Mouse.GetState();
            UpdateMovement(aCurrentKeyboardState);

            if (aCurrentKeyboardState.IsKeyDown(Keys.R))
            {
                Reload();
            }

            weapon.Update(theGameTime);

            mPreviousKeyboardState = aCurrentKeyboardState;
            mPreviousMouseState = aCurrentMouseState;

            hats.Customize_hat = Properties.Settings.Default.Customize_hat;
            Customize_body = Properties.Settings.Default.Customize_body;

            hats.Customize_hat_switch(Properties.Settings.Default.Customize_hat,TheContentManager);
            Customize_body_switch(Properties.Settings.Default.Customize_body,TheContentManager);

            base.Update(theGameTime, mSpeed, mDirection);
        }

        public void UpdateMovement(KeyboardState aCurrentKeyboardState)
        {
            if (mCurrentState == State.Walking)
            {
                mSpeed = Vector2.Zero;
                mDirection = Vector2.Zero;

                if (aCurrentKeyboardState.IsKeyDown(Keys.Left) || aCurrentKeyboardState.IsKeyDown(Keys.A))
                {
                    mSpeed.X = WIZARD_SPEED;
                    mDirection.X = MOVE_LEFT;
                }

                else if (aCurrentKeyboardState.IsKeyDown(Keys.Right) || aCurrentKeyboardState.IsKeyDown(Keys.D))
                {
                    mSpeed.X = WIZARD_SPEED;
                    mDirection.X = MOVE_RIGHT;
                }

                if (aCurrentKeyboardState.IsKeyDown(Keys.Up) || aCurrentKeyboardState.IsKeyDown(Keys.W))
                {
                    mSpeed.Y = WIZARD_SPEED;
                    mDirection.Y = MOVE_UP;
                }

                else if (aCurrentKeyboardState.IsKeyDown(Keys.Down) || aCurrentKeyboardState.IsKeyDown(Keys.S))
                {
                    mSpeed.Y = WIZARD_SPEED;
                    mDirection.Y = MOVE_DOWN;
                }
            }
        }

        private void Recoil(MouseState aCurrentMouseState, MouseState mPreviousMouseState)
        {
            Position.X -= (float)Math.Cos(Rotation) * 5;
            Position.Y -= (float)Math.Sin(Rotation) * 5;
            if (aCurrentMouseState.LeftButton == ButtonState.Released && mPreviousMouseState.LeftButton == ButtonState.Released)
            {
                Position.X += (float)Math.Cos(Rotation) * 5;
                Position.Y += (float)Math.Sin(Rotation) * 5;
            }
        }

        private void Reload()
        {
            uint needed = (weapon.MaxAmmo - weapon.AmmoInClip);

            if (ammo.ForType(weapon.ammoType) > needed)
            {
                ammo.Remove(weapon.ammoType, needed);
                weapon.Reload(needed);
            }
            else
            {
                uint remainder = ammo.ForType(weapon.ammoType);
                ammo.Remove(weapon.ammoType, remainder);
                weapon.Reload(remainder);
            }
        }

        void SignedInGamer_SignedIn(object sender, SignedInEventArgs e)
        {
            if (Gamer.SignedInGamers.Count > 0)
            {
                var gmr = Gamer.SignedInGamers[0];
                Name = gmr.Gamertag;
            }
        }

        #endregion Methods
    }
}